package com.coffee.attachment.excel;

import cn.hutool.core.util.StrUtil;
import com.coffee.excel.MochaExcelException;
import com.coffee.excel.MochaExportHandler;
import com.coffee.excel.MochaImportHandler;
import com.coffee.web.SpringContextBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author: songkui
 * @since: 2023/4/20 17:24
 */
@Slf4j
public class ExcelHandlerManager {

    private final static ConcurrentHashMap<String, MochaExportHandler<?>> exportMapping = new ConcurrentHashMap<>();
    private final static ConcurrentHashMap<String, MochaImportHandler> importHandlerMapping = new ConcurrentHashMap<>();

    private ExcelHandlerManager() {
    }


    public static MochaExportHandler<?> getExportEndpoint(String excelCode) {
        return exportMapping.get(excelCode);
    }

    public static MochaImportHandler getImportHandler(String excelCode) {
        return importHandlerMapping.get(excelCode);
    }


    public static void initializeExportEndpoint(Map<String, MochaExportHandler<?>> handlerMap) {
        exportMapping.putAll(handlerMap);
    }

    public static void initializeImportHandler(Map<String, MochaImportHandler> handlerMap) {
        importHandlerMapping.putAll(handlerMap);
    }


    public static void initializeMapping(String... handlerPackagePaths) throws Exception {
        if (null == handlerPackagePaths || handlerPackagePaths.length == 0) {
            throw new MochaExcelException("MochaExcelHandler package path is null");
        }

        Map<String, MochaExportHandler<?>> exportMap = new HashMap<>();
        Map<String, MochaImportHandler> importMap = new HashMap<>();

        ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
        provider.addIncludeFilter(new AnnotationTypeFilter(ExportHandler.class));
        provider.addIncludeFilter(new AnnotationTypeFilter(ImportHandler.class));
        Set<BeanDefinition> components = null;
        for (String path : handlerPackagePaths) {
            if (StrUtil.isNotBlank(path)) {
                path = path.trim();
                if (null == components) {
                    components = provider.findCandidateComponents(path);
                } else {
                    components.addAll(provider.findCandidateComponents(path));
                }
            }
        }
        if (null == components) {
            log.warn("Package paht  {} MochaExcelHandler Scan handler is null", StrUtil.join(",", (Object[]) handlerPackagePaths));
            return;
        }

        for (BeanDefinition component : components) {
            Class clazz = Class.forName(component.getBeanClassName());
            if (clazz.isAnnotationPresent(ExportHandler.class)) {
                ExportHandler mochaHandler = (ExportHandler) clazz.getAnnotation(ExportHandler.class);
                if (null == mochaHandler || StrUtil.isEmpty(mochaHandler.value())) {
                    throw new MochaExcelException("Excel MochaExcelEndpoint: '" + clazz.getName() + "' MochaExcelEndpoint is null ");
                }
                putExportHandlerMapping(exportMap, mochaHandler.value(), clazz);
            }

            if (clazz.isAnnotationPresent(ImportHandler.class)) {
                ImportHandler mochaHandler = (ImportHandler) clazz.getAnnotation(ImportHandler.class);
                if (null == mochaHandler || StrUtil.isEmpty(mochaHandler.value())) {
                    throw new MochaExcelException("Excel MochaExcelEndpoint: '" + clazz.getName() + "' MochaExcelEndpoint is null ");
                }
                putImportHandlerMapping(importMap, mochaHandler.value(), clazz);
            }
        }

        initializeExportEndpoint(exportMap);
        initializeImportHandler(importMap);
        log.info("Initialize exportHandlerMap size {} success", exportMap.size());
        log.info("Initialize importHandlerMap size {} success", importMap.size());
    }


    private static void putExportHandlerMapping(Map<String, MochaExportHandler<?>> handlerMap, String code, Class<MochaExportHandler<?>> clazz) throws MochaExcelException {
        if (null == clazz || StrUtil.isEmpty(code)) {
            throw new MochaExcelException("build export handler exception");
        }
        handlerMap.put(code, Optional.ofNullable(SpringContextBean.getBean(clazz)).orElseThrow(() -> new MochaExcelException("build export Handler Mapping no exception")));
    }

    private static void putImportHandlerMapping(Map<String, MochaImportHandler> handlerMap, String code, Class<MochaImportHandler> clazz) throws MochaExcelException {
        if (null == clazz || StrUtil.isEmpty(code)) {
            throw new MochaExcelException("build import Handler exception");
        }
        handlerMap.put(code, Optional.ofNullable(SpringContextBean.getBean(clazz)).orElseThrow(() -> new MochaExcelException("build import Handler Mapping no exception")));
    }
}
